babel plugin-transform-runtime 配置和编译结果差异

准备源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// module.js
const foo = () => {
return new Promise(resolve => resolve(1));
};
export const bar = async () => {
await foo();
};
export const far = (...rest) => {
console.log(rest.map(item => item?.aa));
};

// index.js
import { bar, far } from './module';

function* gen() {
const y1 = yield 1;
return y1;
}
const bar1 = async () => {
await far();
};
const p1 = (...rest) => {
return new Promise(resolve => {
resolve(...rest);
});
};

配置 1 : 仅使用 @babel/env

1
2
3
4
5
6
7
8
9
10
11
{
"presets": [
[
"@babel/env",
{
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
]
}

编译结果 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// module.js
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.far = exports.bar = void 0;

require("regenerator-runtime/runtime.js");

require("core-js/modules/es.object.to-string.js");

require("core-js/modules/es.promise.js");

require("core-js/modules/es.array.map.js");

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

var foo = function foo() {
...
};

var bar = /*#__PURE__*/function () {
...
}();

exports.bar = bar;

var far = function far() {
...
};

exports.far = far;

// index.js
"use strict";

require("core-js/modules/es.object.to-string.js");

require("core-js/modules/es.promise.js");

require("regenerator-runtime/runtime.js");

var _module = require("./module");

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

var _marked = /*#__PURE__*/regeneratorRuntime.mark(gen);

function gen() {
...
}

var bar1 = /*#__PURE__*/function () {
...
}();

var p1 = function p1() {
...
};

从结果来看,module.js 和 index.js 都从 core-js 引入了自身需要的 polyfill (全局变量),针对 async/await 分别生成了同样的 asyncGeneratorStep 和 _asyncToGenerator

配置 2 : 使用 @babel/env 和 @babel/plugin-transform-runtime (默认配置)

1
2
3
4
5
6
7
8
9
10
11
12
{
"presets": [
[
"@babel/env",
{
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
],
"plugins": [["@babel/plugin-transform-runtime"]]
}

编译结果 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// module.js
"use strict";

var \_interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "\_\_esModule", {
value: true
});
exports.far = exports.bar = void 0;

var \_regenerator = \_interopRequireDefault(require("@babel/runtime/regenerator"));

var \_asyncToGenerator2 = \_interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
require("core-js/modules/es.object.to-string.js");

require("core-js/modules/es.promise.js");

require("core-js/modules/es.array.map.js");

var foo = function foo() {
...
};

var bar = /_#**PURE**_/function () {
...
}();

exports.bar = bar;

var far = function far() {
};

exports.far = far;

// index.js
"use strict";

var \_interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

require("core-js/modules/es.object.to-string.js");

require("core-js/modules/es.promise.js");

var \_asyncToGenerator2 = \_interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));

var \_regenerator = \_interopRequireDefault(require("@babel/runtime/regenerator"));

var \_module = require("./module");

var \_marked = /_#**PURE**_/\_regenerator.default.mark(gen);

function gen() {
...
}

var bar1 = /_#**PURE**_/function () {
...
}();

var p1 = function p1() {
...
};

添加 @babel/plugin-transform-runtime 后,对于 async/await 不再重复生成 asyncGeneratorStep 和 _asyncToGenerator,改为从 @babel/runtime 中引入, 其余 polyfill 依然从 core-js 引入

配置 3 使用 @babel/env 和 @babel/plugin-transform-runtime (配置 corejs, 需要安装 @babel/runtime-corejs3 依赖)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"presets": [
[
"@babel/env",
{
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}

编译结果 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// module.js
"use strict";

var \_interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");

Object.defineProperty(exports, "\_\_esModule", {
value: true
});
exports.far = exports.bar = void 0;

var \_regenerator = \_interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));

var \_asyncToGenerator2 = \_interopRequireDefault(require("@babel/runtime-corejs3/helpers/asyncToGenerator"));

var \_promise = \_interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));

var \_map = \_interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map"));

var foo = function foo() {
return new \_promise.default(function (resolve) {
return resolve(1);
});
};

var bar = /_#**PURE**_/function () {
...
}();

exports.bar = bar;

var far = function far() {
...
};

exports.far = far;

// index.js
"use strict";

var \_interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");

var \_promise = \_interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));

var \_asyncToGenerator2 = \_interopRequireDefault(require("@babel/runtime-corejs3/helpers/asyncToGenerator"));

var \_regenerator = \_interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));

var \_module = require("./module");

var \_marked = /_#**PURE**_/\_regenerator.default.mark(gen);

function gen() {
...
}

var bar1 = /_#**PURE**_/function () {
...
}();

var p1 = function p1() {
...
};

@babel/plugin-transform-runtime 添加配置 corejs: 3 后,所有的 polyfill 都改为从 @babel/runtime-corejs3 导入,同时由全局覆盖变为了局部变量,不会污染全局

结论:

@babel/presets 的 『”useBuiltIns”: “usage”』会引入模块中需要的 polyfill 并且是全局覆盖的,但是每个模块都会重复生成辅助函数
添加插件 『@babel/plugin-transform-runtime』 后,辅助函数不会在每个模块中重复生成,而是从 『@babel/runtime』引入
@babel/plugin-transform-runtime 进一步配置 『 “corejs”: 3 』后,所有的 polyfill 都从 『@babel/runtime-corejs3』引入,并且是局部变量,不会污染全局

作者

大下坡

发布于

2021-08-05

更新于

2021-08-05

许可协议